import sys
import os
# 添加src目录到Python路径，以便模块间可以正确导入
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))

from flask import Flask, render_template, request, jsonify, flash, redirect, url_for
import pandas as pd
from src.core.trade_processor import TradeProcessor
from src.utils.file_handler import FileHandler
from src.utils.multiplier import get_multiplier
import os
import chardet
import json
from src.adapters.tradingview_adapter import TradingViewAdapter
from src.storage.sqlalchemy_storage import SQLAlchemyStorage
from src.core.models import Base, Trade
import numpy as np
import pytz
from datetime import datetime, timedelta, time
from project_paths import PROJECT_ROOT

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'

# 加载系统配置
def load_system_config():
    config_path = os.path.join(PROJECT_ROOT, 'src', 'config', 'system_config.json')
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Error loading system config: {e}")
        return {
            "trade_colors": {
                "thresholds": {
                    "small_profit": 50,
                    "small_loss": -50,
                    "large_profit": 500,
                    "large_loss": -500
                },
                "colors": {
                    "small_profit": "#808080",
                    "small_loss": "#808080",
                    "profit": "#28a745",
                    "loss": "#dc3545",
                    "large_profit": "#007bff",
                    "large_loss": "#6f42c1"
                }
            }
        }

# 加载交易类型配置
def load_trade_config():
    config_path = os.path.join(PROJECT_ROOT, 'src', 'config', 'trade_config.json')
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Error loading trade config: {e}")
        return {"trade_types": []}

# 初始化组件
file_handler = FileHandler()
platform_adapter = TradingViewAdapter()
db_dir = os.path.join(PROJECT_ROOT, 'db')
print("db_dir:", db_dir)
if not os.path.exists(db_dir):
    os.makedirs(db_dir)
storage = SQLAlchemyStorage(
    db_path=os.path.join(db_dir, 'trades.db')
)

# 确保数据库表已创建
# Base.metadata.create_all(storage.engine) # create_all已在SQLAlchemyStorage的__init__中调用

trade_processor = TradeProcessor(platform_adapter, storage)
system_config = load_system_config()
trade_config = load_trade_config()

def trades_to_df(trades: list) -> pd.DataFrame:
    # 将SQLAlchemy ORM对象列表转换为DataFrame
    data = []
    for t in trades:
        # 将ORM对象转换为字典，并处理datetime对象
        d = {key: getattr(t, key) for key in t.__table__.columns.keys()}
        for col in ['open_datetime', 'close_datetime']:
            if col in d and hasattr(d[col], 'isoformat'):
                d[col] = d[col].isoformat()
            elif col in d and d[col] is None:
                d[col] = ''
        data.append(d)
    df = pd.DataFrame(data)
    # 保证所有时间字段为字符串
    for col in ['open_datetime', 'close_datetime']:
        if col in df.columns:
            df[col] = df[col].apply(lambda x: x.isoformat() if hasattr(x, 'isoformat') else str(x) if x is not None else '')
    return df

@app.route('/')
def index():
    """主页"""
    return redirect(url_for('trades'))

@app.route('/trades')
def trades():
    """交易列表页面"""
    trades_df = trades_to_df(storage.get_trades())
    # 确保所有可能为空的列都存在，否则DataTables会报错
    all_display_fields = [
        'index', 'trade_id', 'symbol', 'open_datetime', 'close_datetime', 'open_price', 'open_qty', 'close_price', 'close_qty',
        'direction', 'open_order_type', 'trade_type', 'side', 'holding_time', 'nth_trade', 'session',
        'point_profit_per_lot', 'total_points', 'gross_profit', 'net_profit', 'commission',
        'max_floating_profit_points', 'max_floating_profit_dollars', 'max_floating_loss_points', 'max_floating_loss_dollars',
        'entry_reason', 'exit_reason', 'stop_loss_price', 'stop_loss_reason', 'take_profit_price', 'take_profit_reason', 'rating', 'evaluation', 'open_rrr', 'close_rrr', 'fwr', 'actual_risk', 'extend', 'prr'
    ]
    for col in all_display_fields:
        if col not in trades_df.columns:
            trades_df[col] = '' # 填充空字符串
    return render_template('trades.html', 
                         trades=trades_df.to_dict('records'), 
                         system_config=system_config,
                         trade_types=trade_config['trade_types'],
                         entry_reasons=trade_config.get('entry_reasons', []),
                         exit_reasons=trade_config.get('exit_reasons', []),
                         stop_loss_reasons=trade_config.get('stop_loss_reasons', []),
                         take_profit_reasons=trade_config.get('stop_loss_reasons', []),
                         side_options=trade_config.get('side_options', []),
                         column_widths=system_config.get('column_widths', {}))

@app.route('/trades_api')
def trades_api():
    trades_df = trades_to_df(storage.get_trades())
    all_fields = [
        'trade_id', 'symbol', 'open_datetime', 'close_datetime', 'open_price', 'open_qty', 'close_price', 'close_qty',
        'direction', 'open_order_type', 'trade_type', 'side', 'holding_time', 'nth_trade', 'session',
        'point_profit_per_lot', 'total_points', 'gross_profit', 'net_profit', 'commission',
        'max_floating_profit_points', 'max_floating_profit_dollars', 'max_floating_loss_points', 'max_floating_loss_dollars',
        'entry_reason', 'exit_reason', 'stop_loss_price', 'stop_loss_reason', 'take_profit_price', 'take_profit_reason', 'rating', 'evaluation', 'open_rrr', 'close_rrr'
    ]
    for col in all_fields:
        if col not in trades_df.columns:
            trades_df[col] = ''
    return jsonify(trades_df[all_fields].fillna('').to_dict('records'))

@app.route('/import_orders', methods=['POST'])
def import_orders():
    if 'file' not in request.files:
        if request.accept_mimetypes['application/json']:
            return jsonify({'success': False, 'error': '没有选择文件'}), 400
        flash('没有选择文件', 'error')
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        if request.accept_mimetypes['application/json']:
            return jsonify({'success': False, 'error': '没有选择文件'}), 400
        flash('没有选择文件', 'error')
        return redirect(request.url)
    if file and file.filename.endswith('.csv'):
        try:
            raw_data = file.read()
            result = chardet.detect(raw_data)
            encoding = result['encoding']
            file.seek(0)
            df = pd.read_csv(file, encoding=encoding)
            def recalculate_commission(row, fee_config):
                symbol = row['Symbol']
                qty = abs(float(row['Qty']))
                base_symbol = symbol[:-3] if len(symbol) > 3 else symbol
                extra_fee_multiplier = fee_config.get(base_symbol, 0)
                extra_fee = extra_fee_multiplier * qty
                original_fee = float(row['Commission Fee']) if pd.notna(row['Commission Fee']) else 0
                return original_fee + extra_fee
            commission_config = trade_config.get('extra_commission_fees', {}) if trade_config else {}
            df['Commission Fee'] = df.apply(lambda row: recalculate_commission(row, commission_config), axis=1)
            column_mapping = {
                'Order ID': 'order_id',
                'Symbol': 'symbol',
                'Side': 'side',
                'Type': 'order_type',
                'Qty': 'quantity',
                'Filled Qty': 'filled',
                'Qty Left': 'quantity_left',
                'Limit Price': 'limit_price',
                'Stop Price': 'stop_price',
                'Avg Fill Price': 'avg_fill_price',
                'Status': 'status',
                'Open Time': 'open_time',
                'Close Time': 'close_time',
                'Duration': 'duration',
                'Commission Fee': 'commission',
                'Expiration Date': 'expiration'
            }
            df = df.rename(columns=column_mapping)
            required_columns = [
                'order_id', 'symbol', 'side', 'order_type', 'quantity', 'filled',
                'quantity_left', 'limit_price', 'stop_price', 'avg_fill_price', 'status',
                'open_time', 'close_time', 'duration', 'commission', 'expiration'
            ]
            for col in required_columns:
                if col not in df.columns:
                    df[col] = None
            df = df[required_columns]
            df['multiplier'] = df['symbol'].apply(lambda x: get_multiplier(x[:-3] if len(x) > 3 else x))
            result = trade_processor.process_new_orders(df)
            
            # 提取结果
            new_trades = result['new_trades']
            duplicate_orders = result['duplicate_orders']
            duplicate_trades = result['duplicate_trades']
            save_orders_result = result['save_orders_result']
            save_trades_success = result['save_trades_success']
            
            # 构建详细的响应信息
            success_message = ''
            warning_messages = []
            error_messages = []
            
            # 检查交易保存结果
            if save_trades_success:
                success_message = f'成功导入 {len(new_trades)} 笔新交易'
            else:
                error_messages.append(f'交易保存失败，导入了 {len(new_trades)} 笔交易但未能保存到数据库')
            
            # 检查订单保存结果
            if save_orders_result:
                if save_orders_result['success']:
                    if success_message:
                        success_message += f'，保存了 {save_orders_result["saved_count"]} 个新订单'
                    else:
                        success_message = f'保存了 {save_orders_result["saved_count"]} 个新订单'
                    if save_orders_result['duplicate_count'] > 0:
                        error_messages.append(f'在保存时，跳过了 {save_orders_result["duplicate_count"]} 个重复订单: {", ".join(save_orders_result["duplicate_orders"][:5])}{"..." if len(save_orders_result["duplicate_orders"]) > 5 else ""}')
                else:
                    error_messages.append(f'保存订单时出错: {save_orders_result["error"]}')
            
            # 检查重复的处理订单
            if len(duplicate_orders) > 0:
                warning_messages.append(f'发现 {len(duplicate_orders)} 笔重复的处理订单')
            
            # 检查重复的交易
            if len(duplicate_trades) > 0:
                warning_messages.append(f'发现 {len(duplicate_trades)} 笔重复交易')
            
            # 判断整体是否成功（交易和订单都必须保存成功）
            overall_success = save_trades_success and (not save_orders_result or save_orders_result['success']) and len(error_messages) == 0
            
            if request.accept_mimetypes['application/json']:
                return jsonify({
                    'success': overall_success,
                    'success_message': success_message if success_message else None,
                    'warning_messages': warning_messages if warning_messages else None,
                    'error_messages': error_messages if error_messages else None,
                    'statistics': {
                        'new_trades_count': len(new_trades),
                        'duplicate_orders_count': len(duplicate_orders),
                        'duplicate_trades_count': len(duplicate_trades),
                        'saved_orders_count': save_orders_result['saved_count'] if save_orders_result and save_orders_result['success'] else 0,
                        'duplicate_saved_orders_count': save_orders_result['duplicate_count'] if save_orders_result else 0,
                        'trades_saved_successfully': save_trades_success
                    }
                })
            
            # 始终显示成功消息（即使有错误）
            if success_message:
                flash(success_message, 'success')
            
            # 始终显示警告消息（即使有错误）
            for warning in warning_messages:
                flash(warning, 'warning')
            
            # 显示错误消息
            for error in error_messages:
                flash(error, 'error')
            
            return redirect(url_for('index'))
        except Exception as e:
            if request.accept_mimetypes['application/json']:
                return jsonify({'success': False, 'error': str(e)}), 400
            flash(f'导入订单时出错: {str(e)}', 'error')
            return redirect(request.url)
    if request.accept_mimetypes['application/json']:
        return jsonify({'success': False, 'error': '请上传CSV文件'}), 400
    flash('请上传CSV文件', 'error')
    return redirect(request.url)

@app.route('/edit_trade/<int:trade_id>', methods=['GET', 'POST'])
def edit_trade(trade_id):
    """编辑交易页面"""
    # SQLAlchemy ORM下，trade_id通常是唯一的，这里可能需要调整查询方式
    # 假设trade_id是Trade ORM对象的trade_id属性
    session = storage._get_session() # 获取SQLAlchemy Session
    trade_obj = session.query(Trade).filter_by(trade_id=str(trade_id)).first() # 按trade_id查询
    session.close()

    if not trade_obj:
        flash('Trade not found', 'error')
        return redirect(url_for('trades'))

    # 将ORM对象转换为字典以便模板渲染
    trade = {key: getattr(trade_obj, key) for key in trade_obj.__table__.columns.keys()}
    # 处理datetime对象，转换为ISO格式字符串
    for col in ['open_datetime', 'close_datetime']:
        if col in trade and hasattr(trade[col], 'isoformat'):
            trade[col] = trade[col].isoformat().split('T')[0] # 只保留日期部分给input type='date'

    if request.method == 'POST':
        updated_data = request.form.to_dict()
        # Flask的request.form将所有数据作为字符串处理，需要手动转换类型
        # 对于datetime字段，需要从字符串转回datetime对象
        for k, v in updated_data.items():
            if k in ['open_datetime', 'close_datetime']:
                try:
                    updated_data[k] = datetime.fromisoformat(v) if v else None
                except ValueError:
                    updated_data[k] = None
            elif k in ['open_price', 'open_qty', 'close_price', 'close_qty', 'point_profit_per_lot', 'total_points',
                      'gross_profit', 'net_profit', 'commission', 'max_floating_profit_points',
                      'max_floating_profit_dollars', 'max_floating_loss_points', 'max_floating_loss_dollars',
                      'stop_loss_price', 'take_profit_price']:
                try:
                    updated_data[k] = float(v) if v else None
                except ValueError:
                    updated_data[k] = None
            elif k == 'nth_trade':
                try:
                    updated_data[k] = int(v) if v else None
                except ValueError:
                    updated_data[k] = None

        success = storage.update_trade(trade_id, updated_data)
        if success:
            flash('Trade updated successfully', 'success')
            return redirect(url_for('trades'))
        else:
            flash('Failed to update trade', 'error')
            return redirect(request.url)
    
    return render_template('edit_trade.html', trade=trade)

@app.route('/statistics/data', methods=['GET'])
def statistics_data():
    """获取统计数据，支持过滤参数"""
    trades_df = trades_to_df(storage.get_trades())
    n = int(request.args.get('n', 5))
    start_date = request.args.get('start_date')
    end_date = request.args.get('end_date')
    
    # 调试：打印所有请求参数
    print("=== 后端接收到的请求参数 ===")
    print("request.args:", dict(request.args))
    print("request.args.lists():", dict(request.args.lists()))
    
    # 时间过滤
    if start_date:
        trades_df = trades_df[trades_df['open_datetime'] >= start_date]
    if end_date:
        trades_df = trades_df[trades_df['open_datetime'] <= end_date + ' 23:59:59']
    
    # 过滤参数
    symbols = request.args.getlist('symbols')  # 品种列表
    print("symbols from getlist:", symbols)
    directions = request.args.getlist('directions')  # 方向列表
    trade_types = request.args.getlist('trade_types')  # 交易类型列表
    sessions = request.args.getlist('sessions')  # 时段列表
    sides = request.args.getlist('sides')  # Side列表
    entry_reasons = request.args.getlist('entry_reasons')  # 入场理由列表
    stop_loss_reasons = request.args.getlist('stop_loss_reasons')  # 止损理由列表
    take_profit_reasons = request.args.getlist('take_profit_reasons')  # 止盈理由列表
    other_exit_reasons = request.args.getlist('other_exit_reasons')  # 其他离场理由列表
    profit_status = request.args.get('profit_status')  # 盈亏状态
    profit_min = request.args.get('profit_min')  # 最小净利润
    profit_max = request.args.get('profit_max')  # 最大净利润
    duration_min = request.args.get('duration_min')  # 最小持仓时间(分钟)
    duration_max = request.args.get('duration_max')  # 最大持仓时间(分钟)
    
    # 应用过滤条件
    filtered_df = apply_trade_filters(trades_df, {
        'symbols': symbols,
        'directions': directions,
        'trade_types': trade_types,
        'sessions': sessions,
        'sides': sides,
        'entry_reasons': entry_reasons,
        'stop_loss_reasons': stop_loss_reasons,
        'take_profit_reasons': take_profit_reasons,
        'other_exit_reasons': other_exit_reasons,
        'profit_status': profit_status,
        'profit_min': profit_min,
        'profit_max': profit_max,
        'duration_min': duration_min,
        'duration_max': duration_max
    })
    
    stats = trade_processor.calculate_statistics(filtered_df, max_n=n)
    
    def nan_to_none(obj):
        if isinstance(obj, dict):
            return {k: nan_to_none(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [nan_to_none(v) for v in obj]
        elif isinstance(obj, float) and (obj != obj or obj == float('inf') or obj == float('-inf')):
            return None
        else:
            return obj
    
    stats = nan_to_none(stats)
    
    # 添加过滤信息到统计结果
    stats['filter_info'] = {
        'total_trades_before_filter': len(trades_df),
        'total_trades_after_filter': len(filtered_df),
        'filter_applied': any([symbols, directions, trade_types, sessions, sides, entry_reasons, stop_loss_reasons, take_profit_reasons, other_exit_reasons,
                              profit_status, profit_min, profit_max, duration_min, duration_max])
    }
    
    return jsonify(stats)

def apply_trade_filters(df, filters):
    """应用交易过滤条件"""
    if df.empty:
        return df
    
    filtered_df = df.copy()
    
    # 品种过滤 (不区分大小写)
    if filters.get('symbols') and '' not in filters['symbols']:
        symbols_lower = [s.lower() for s in filters['symbols']]
        filtered_df = filtered_df[filtered_df['symbol'].str.lower().isin(symbols_lower)]
    
    # 方向过滤 (不区分大小写)
    if filters.get('directions') and '' not in filters['directions']:
        directions_lower = [d.lower() for d in filters['directions']]
        filtered_df = filtered_df[filtered_df['direction'].str.lower().isin(directions_lower)]
    
    # 交易类型过滤 (不区分大小写)
    if filters.get('trade_types') and '' not in filters['trade_types']:
        trade_types_lower = [t.lower() for t in filters['trade_types']]
        filtered_df = filtered_df[filtered_df['trade_type'].str.lower().isin(trade_types_lower)]
    
    # 时段过滤 (不区分大小写)
    if filters.get('sessions') and '' not in filters['sessions']:
        sessions_lower = [s.lower() for s in filters['sessions']]
        filtered_df = filtered_df[filtered_df['session'].str.lower().isin(sessions_lower)]
    
    # Side过滤 (不区分大小写)
    if filters.get('sides') and '' not in filters['sides']:
        sides_lower = [s.lower() for s in filters['sides']]
        # 处理空值情况
        filtered_df = filtered_df[
            (filtered_df['side'].notna()) & 
            (filtered_df['side'].str.lower().isin(sides_lower))
        ]
    
    # 入场理由过滤 (不区分大小写)
    if filters.get('entry_reasons') and '' not in filters['entry_reasons']:
        entry_reasons_lower = [e.lower() for e in filters['entry_reasons']]
        filtered_df = filtered_df[filtered_df['entry_reason'].str.lower().isin(entry_reasons_lower)]
    
    # 止损理由过滤 (不区分大小写)
    if filters.get('stop_loss_reasons') and '' not in filters['stop_loss_reasons']:
        stop_loss_reasons_lower = [s.lower() for s in filters['stop_loss_reasons']]
        filtered_df = filtered_df[filtered_df['stop_loss_reason'].str.lower().isin(stop_loss_reasons_lower)]
    
    # 止盈理由过滤 (不区分大小写)
    if filters.get('take_profit_reasons') and '' not in filters['take_profit_reasons']:
        take_profit_reasons_lower = [t.lower() for t in filters['take_profit_reasons']]
        filtered_df = filtered_df[filtered_df['take_profit_reason'].str.lower().isin(take_profit_reasons_lower)]
    
    # 其他离场理由过滤 (不区分大小写)
    if filters.get('other_exit_reasons') and '' not in filters['other_exit_reasons']:
        other_exit_reasons_lower = [o.lower() for o in filters['other_exit_reasons']]
        filtered_df = filtered_df[filtered_df['exit_reason'].str.lower().isin(other_exit_reasons_lower)]
    
    # 盈亏状态过滤
    if filters.get('profit_status'):
        profit_status = filters['profit_status']
        if profit_status == 'profitable':
            filtered_df = filtered_df[filtered_df['net_profit'] > 0]
        elif profit_status == 'losing':
            filtered_df = filtered_df[filtered_df['net_profit'] < 0]
        elif profit_status == 'breakeven':
            filtered_df = filtered_df[filtered_df['net_profit'] == 0]
    
    # 净利润范围过滤
    if filters.get('profit_min'):
        try:
            profit_min = float(filters['profit_min'])
            filtered_df = filtered_df[filtered_df['net_profit'] >= profit_min]
        except (ValueError, TypeError):
            pass
    
    if filters.get('profit_max'):
        try:
            profit_max = float(filters['profit_max'])
            filtered_df = filtered_df[filtered_df['net_profit'] <= profit_max]
        except (ValueError, TypeError):
            pass
    
    # 持仓时间过滤 (将holding_time转换为分钟)
    if filters.get('duration_min') or filters.get('duration_max'):
        # 将holding_time转换为分钟数
        def parse_duration_to_minutes(duration_str):
            try:
                if pd.isna(duration_str) or duration_str == '':
                    return 0
                # 格式: "HH:MM:SS" 或 "MM:SS"
                parts = str(duration_str).split(':')
                if len(parts) == 3:  # HH:MM:SS
                    hours, minutes, seconds = map(int, parts)
                    return hours * 60 + minutes + seconds / 60.0
                elif len(parts) == 2:  # MM:SS
                    minutes, seconds = map(int, parts)
                    return minutes + seconds / 60.0
                else:
                    return 0
            except:
                return 0
        
        filtered_df['duration_minutes'] = filtered_df['holding_time'].apply(parse_duration_to_minutes)
        
        if filters.get('duration_min'):
            try:
                duration_min = float(filters['duration_min'])
                filtered_df = filtered_df[filtered_df['duration_minutes'] >= duration_min]
            except (ValueError, TypeError):
                pass
        
        if filters.get('duration_max'):
            try:
                duration_max = float(filters['duration_max'])
                filtered_df = filtered_df[filtered_df['duration_minutes'] <= duration_max]
            except (ValueError, TypeError):
                pass
        
        # 移除临时列
        filtered_df = filtered_df.drop('duration_minutes', axis=1)
    
    return filtered_df

@app.route('/update_trade', methods=['POST'])
def update_trade():
    try:
        print("update_trade called1 ", request.form)
        trade_id = request.form.get('trade_id')
        field = request.form.get('field')
        value = request.form.get('value')
        print("update_trade called", trade_id, field, value)
        
        if not all([trade_id, field]):
            return jsonify({'success': False, 'message': '缺少必要参数'})
        
        # 构建更新字典
        updates = {field: value}
        
        # 检查是否有额外的字段需要更新
        for key in request.form:
            if key not in ['trade_id', 'field', 'value']:
                updates[key] = request.form.get(key)
        
        # 更新交易记录
        success = storage.update_trade(trade_id, updates)
        
        if success:
            return jsonify({'success': True})
        else:
            return jsonify({'success': False, 'message': '更新失败'})
            
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

@app.route('/delete_trade', methods=['POST'])
def delete_trade():
    try:
        trade_id = request.form.get('trade_id')
        
        if not trade_id:
            return jsonify({'success': False, 'message': '缺少交易ID'})
        
        # 删除交易记录
        success = storage.delete_trade(trade_id)
        
        if success:
            return jsonify({'success': True})
        else:
            return jsonify({'success': False, 'message': '删除失败'})
            
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

@app.route('/get_trade_calculations', methods=['POST'])
def get_trade_calculations():
    try:
        trade_id = request.form.get('trade_id')
        if not trade_id:
            return jsonify({'success': False, 'message': '缺少交易ID'})
        
        # 从trade_id中解析开平仓时间
        # SQLAlchemy ORM下，直接通过trade_id查询即可
        # open_datetime, close_datetime = trade_id.split('_') # This line is no longer needed
        
        session = storage._get_session()
        trade = session.query(Trade).filter_by(trade_id=trade_id).first()
        session.close()

        if not trade:
            return jsonify({'success': False, 'message': 'Trade not found'})
        
        # 返回计算字段
        return jsonify({
            'success': True,
            'gross_profit': float(trade.gross_profit) if trade.gross_profit is not None else None,
            'net_profit': float(trade.net_profit) if trade.net_profit is not None else None,
            'commission': float(trade.commission) if trade.commission is not None else None
        })
            
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

@app.route('/update_trade_type', methods=['POST'])
def update_trade_type():
    """更新交易类型"""
    try:
        trade_id = request.form.get('trade_id')
        trade_type = request.form.get('trade_type')
        
        if not trade_id:
            return jsonify({'success': False, 'error': '缺少交易ID'})
            
        # 更新交易类型
        success = storage.update_trade(trade_id, {'trade_type': trade_type})
        
        if success:
            return jsonify({'success': True})
        else:
            return jsonify({'success': False, 'error': '更新失败'})
    except Exception as e:
        print(f"Error updating trade type: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/statistics')
def statistics_page():
    """统计页面"""
    return render_template('statistics.html')



@app.route('/statistics/filter_options')
def get_filter_options():
    """获取过滤器的选项数据"""
    try:
        # 从trade_config.json中读取配置选项
        config_options = {
            'trade_types': trade_config.get('trade_types', []),
            'entry_reasons': trade_config.get('entry_reasons', []),
            'exit_reasons': trade_config.get('exit_reasons', []),
            'stop_loss_reasons': trade_config.get('stop_loss_reasons', []),
            'sessions': ['RTH', 'ETH']  # 固定的时段选项
        }
        
        print("config_options", config_options)

        # 处理止盈理由：如果配置为"复用止损理由"，则使用止损理由列表
        take_profit_config = trade_config.get('take_profit_reasons', [])
        if take_profit_config and take_profit_config[0] == "复用止损理由":
            config_options['take_profit_reasons'] = config_options['stop_loss_reasons']
        else:
            config_options['take_profit_reasons'] = take_profit_config
        
        # 从数据库中获取动态数据（品种列表）
        trades_df = trades_to_df(storage.get_trades())
        
        # 获取唯一的品种列表（从数据库动态获取）
        symbols = []
        if not trades_df.empty:
            symbols = sorted(trades_df['symbol'].dropna().unique().tolist())
            symbols = [s for s in symbols if s and str(s).strip()]
        
        return jsonify({
            'symbols': symbols,
            'trade_types': config_options['trade_types'],
            'sessions': config_options['sessions'],
            'entry_reasons': config_options['entry_reasons'],
            'stop_loss_reasons': config_options['stop_loss_reasons'],
            'take_profit_reasons': config_options['take_profit_reasons'],
            'other_exit_reasons': config_options['exit_reasons']
        })
        
    except Exception as e:
        print(f"Error getting filter options: {e}")
        return jsonify({
            'symbols': [],
            'trade_types': [],
            'sessions': ['RTH', 'ETH'],
            'entry_reasons': [],
            'stop_loss_reasons': [],
            'take_profit_reasons': [],
            'other_exit_reasons': []
        })

@app.route('/statistics/saved_filters')
def get_saved_filters():
    """获取已保存的过滤器列表"""
    try:
        filters_file = os.path.join(PROJECT_ROOT, 'data', 'saved_filters.json')
        if os.path.exists(filters_file):
            with open(filters_file, 'r', encoding='utf-8') as f:
                filters = json.load(f)
        else:
            filters = []
        return jsonify({'filters': filters})
    except Exception as e:
        print(f"Error getting saved filters: {e}")
        return jsonify({'filters': []})

@app.route('/statistics/save_filter', methods=['POST'])
def save_filter():
    """保存过滤器"""
    try:
        data = request.get_json()
        filter_name = data.get('name')
        filter_conditions = data.get('conditions')
        
        if not filter_name or not filter_conditions:
            return jsonify({'success': False, 'message': '过滤器名称和条件不能为空'})
        
        # 确保data目录存在
        data_dir = os.path.join(PROJECT_ROOT, 'data')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        filters_file = os.path.join(data_dir, 'saved_filters.json')
        
        # 读取现有过滤器
        if os.path.exists(filters_file):
            with open(filters_file, 'r', encoding='utf-8') as f:
                filters = json.load(f)
        else:
            filters = []
        
        # 检查是否已存在同名过滤器
        existing_filter = next((f for f in filters if f['name'] == filter_name), None)
        if existing_filter:
            return jsonify({'success': False, 'message': '已存在同名过滤器，请使用其他名称'})
        
        # 添加新过滤器
        new_filter = {
            'id': len(filters) + 1,
            'name': filter_name,
            'conditions': filter_conditions,
            'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        filters.append(new_filter)
        
        # 保存到文件
        with open(filters_file, 'w', encoding='utf-8') as f:
            json.dump(filters, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '过滤器保存成功'})
        
    except Exception as e:
        print(f"Error saving filter: {e}")
        return jsonify({'success': False, 'message': f'保存失败: {str(e)}'})

@app.route('/statistics/delete_filter', methods=['POST'])
def delete_filter():
    """删除过滤器"""
    try:
        data = request.get_json()
        filter_id = data.get('id')
        
        if not filter_id:
            return jsonify({'success': False, 'message': '过滤器ID不能为空'})
        
        filters_file = os.path.join(PROJECT_ROOT, 'data', 'saved_filters.json')
        
        if not os.path.exists(filters_file):
            return jsonify({'success': False, 'message': '没有找到保存的过滤器'})
        
        # 读取现有过滤器
        with open(filters_file, 'r', encoding='utf-8') as f:
            filters = json.load(f)
        
        # 查找并删除过滤器
        original_count = len(filters)
        filters = [f for f in filters if f['id'] != filter_id]
        
        if len(filters) == original_count:
            return jsonify({'success': False, 'message': '未找到指定的过滤器'})
        
        # 保存更新后的过滤器列表
        with open(filters_file, 'w', encoding='utf-8') as f:
            json.dump(filters, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '过滤器删除成功'})
        
    except Exception as e:
        print(f"Error deleting filter: {e}")
        return jsonify({'success': False, 'message': f'删除失败: {str(e)}'})

# 图表配置管理API接口
@app.route('/statistics/saved_chart_configs')
def get_saved_chart_configs():
    """获取保存的图表配置"""
    try:
        configs_file = os.path.join(PROJECT_ROOT, 'data', 'saved_chart_configs.json')
        
        if not os.path.exists(configs_file):
            return jsonify({'configs': []})
        
        with open(configs_file, 'r', encoding='utf-8') as f:
            configs = json.load(f)
        
        return jsonify({'configs': configs})
    except Exception as e:
        print(f"Error getting saved chart configs: {e}")
        return jsonify({'configs': []})

@app.route('/statistics/save_chart_config', methods=['POST'])
def save_chart_config():
    """保存图表配置"""
    try:
        data = request.get_json()
        config_name = data.get('name')
        chart_config = data.get('config')
        
        if not config_name or not chart_config:
            return jsonify({'success': False, 'message': '配置名称和配置内容不能为空'})
        
        # 确保data目录存在
        data_dir = os.path.join(PROJECT_ROOT, 'data')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        configs_file = os.path.join(data_dir, 'saved_chart_configs.json')
        
        # 读取现有配置
        if os.path.exists(configs_file):
            with open(configs_file, 'r', encoding='utf-8') as f:
                configs = json.load(f)
        else:
            configs = []
        
        # 检查是否已存在同名配置
        existing_config = next((c for c in configs if c['name'] == config_name), None)
        if existing_config:
            return jsonify({'success': False, 'message': '已存在同名配置，请使用其他名称'})
        
        # 添加新配置
        new_config = {
            'id': max([c.get('id', 0) for c in configs], default=0) + 1,
            'name': config_name,
            'config': chart_config,
            'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        configs.append(new_config)
        
        # 保存到文件
        with open(configs_file, 'w', encoding='utf-8') as f:
            json.dump(configs, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '图表配置保存成功'})
        
    except Exception as e:
        print(f"Error saving chart config: {e}")
        return jsonify({'success': False, 'message': f'保存失败: {str(e)}'})

@app.route('/statistics/update_chart_config', methods=['POST'])
def update_chart_config():
    """更新图表配置"""
    try:
        data = request.get_json()
        config_id = data.get('id')
        chart_config = data.get('config')
        
        if not config_id or not chart_config:
            return jsonify({'success': False, 'message': '配置ID和配置内容不能为空'})
        
        configs_file = os.path.join(PROJECT_ROOT, 'data', 'saved_chart_configs.json')
        
        if not os.path.exists(configs_file):
            return jsonify({'success': False, 'message': '没有找到保存的配置'})
        
        # 读取现有配置
        with open(configs_file, 'r', encoding='utf-8') as f:
            configs = json.load(f)
        
        # 查找并更新配置
        config_found = False
        for config in configs:
            if config['id'] == config_id:
                config['config'] = chart_config
                config['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                config_found = True
                break
        
        if not config_found:
            return jsonify({'success': False, 'message': '未找到指定的配置'})
        
        # 保存更新后的配置列表
        with open(configs_file, 'w', encoding='utf-8') as f:
            json.dump(configs, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '配置更新成功'})
        
    except Exception as e:
        print(f"Error updating chart config: {e}")
        return jsonify({'success': False, 'message': f'更新失败: {str(e)}'})

@app.route('/statistics/delete_chart_config', methods=['POST'])
def delete_chart_config():
    """删除图表配置"""
    try:
        data = request.get_json()
        config_id = data.get('id')
        
        if not config_id:
            return jsonify({'success': False, 'message': '配置ID不能为空'})
        
        configs_file = os.path.join(PROJECT_ROOT, 'data', 'saved_chart_configs.json')
        
        if not os.path.exists(configs_file):
            return jsonify({'success': False, 'message': '没有找到保存的配置'})
        
        # 读取现有配置
        with open(configs_file, 'r', encoding='utf-8') as f:
            configs = json.load(f)
        
        # 查找并删除配置
        original_count = len(configs)
        configs = [c for c in configs if c['id'] != config_id]
        
        if len(configs) == original_count:
            return jsonify({'success': False, 'message': '未找到指定的配置'})
        
        # 保存更新后的配置列表
        with open(configs_file, 'w', encoding='utf-8') as f:
            json.dump(configs, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '配置删除成功'})
        
    except Exception as e:
        print(f"Error deleting chart config: {e}")
        return jsonify({'success': False, 'message': f'删除失败: {str(e)}'})

# 快速配置管理API接口
@app.route('/statistics/quick_config_settings', methods=['GET'])
def get_quick_config_settings():
    """获取快速配置设置"""
    try:
        settings_file = os.path.join(PROJECT_ROOT, 'data', 'quick_config_settings.json')
        
        if not os.path.exists(settings_file):
            # 返回默认设置
            default_settings = {
                'configs': [],
                'limit': 10,
                'style': 'outline'
            }
            return jsonify({'success': True, 'settings': default_settings})
        
        with open(settings_file, 'r', encoding='utf-8') as f:
            settings = json.load(f)
        
        return jsonify({'success': True, 'settings': settings})
    except Exception as e:
        print(f"Error getting quick config settings: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/statistics/quick_config_settings', methods=['POST'])
def save_quick_config_settings():
    """保存快速配置设置"""
    try:
        data = request.get_json()
        
        if not data:
            return jsonify({'success': False, 'error': '请求数据为空'})
        
        # 验证数据结构
        if 'configs' not in data or 'limit' not in data or 'style' not in data:
            return jsonify({'success': False, 'error': '数据结构不正确'})
        
        # 确保data目录存在
        data_dir = os.path.join(PROJECT_ROOT, 'data')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        settings_file = os.path.join(data_dir, 'quick_config_settings.json')
        
        # 添加时间戳
        data['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        
        # 保存设置
        with open(settings_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '快速配置设置保存成功'})
        
    except Exception as e:
        print(f"Error saving quick config settings: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/statistics/multi_chart_state')
def get_multi_chart_state():
    """获取多图表状态"""
    try:
        state_file = os.path.join(PROJECT_ROOT, 'data', 'multi_chart_state.json')
        
        if os.path.exists(state_file):
            with open(state_file, 'r', encoding='utf-8') as f:
                state = json.load(f)
            return jsonify({'success': True, 'state': state})
        else:
            return jsonify({'success': True, 'state': None})
    
    except Exception as e:
        print(f"Error loading multi chart state: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/statistics/multi_chart_state', methods=['POST'])
def save_multi_chart_state():
    """保存多图表状态"""
    try:
        data = request.get_json()
        chart_instances = data.get('chartInstances', [])
        
        # 创建状态对象
        state = {
            'chartInstances': chart_instances,
            'timestamp': datetime.now().isoformat(),
            'version': '1.0'
        }
        
        # 确保data目录存在
        data_dir = os.path.join(PROJECT_ROOT, 'data')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        state_file = os.path.join(data_dir, 'multi_chart_state.json')
        
        with open(state_file, 'w', encoding='utf-8') as f:
            json.dump(state, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'message': '图表状态保存成功'})
    
    except Exception as e:
        print(f"Error saving multi chart state: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/statistics/trades_in_period')
def trades_in_period():
    start = request.args.get('start')
    end = request.args.get('end')
    # 纽约时区
    tz_ny = pytz.timezone('America/New_York')
    #tz_bj = pytz.timezone('Asia/Shanghai') # Unused

    # 从ORM获取Trade对象列表，然后转换为DataFrame
    trades_from_db = storage.get_trades()

    # 常用时区:
    # - Asia/Shanghai (北京时间)
    # - America/New_York (纽约时间)
    # - Asia/Tokyo (东京时间)
    # - Asia/Singapore (新加坡时间)
    # - Europe/Berlin (柏林时间)
    # - Europe/London (伦敦时间)
    # - Europe/Paris (巴黎时间)
    # - Europe/Rome (罗马时间)
    # - Europe/Madrid (马德里时间)
    # - Europe/Amsterdam (阿姆斯特丹时间)
    # - Europe/Brussels (布鲁塞尔时间)
    def add_timezone(trade, timezone):
        if trade.open_datetime:
            trade.open_datetime = trade.open_datetime.astimezone(pytz.timezone(timezone))
        if trade.close_datetime:
            trade.close_datetime = trade.close_datetime.astimezone(pytz.timezone(timezone))
        return trade
    trades_from_db = [add_timezone(trade, 'Asia/Shanghai') for trade in trades_from_db]
    
    df = trades_to_df(trades_from_db)
    
    # 确保 open_datetime 是 datetime 类型，以便后续操作
    df['open_datetime'] = pd.to_datetime(df['open_datetime'])
    df['close_datetime'] = pd.to_datetime(df['close_datetime'])

    # 转为纽约时间
    df['open_datetime_ny'] = df['open_datetime'].dt.tz_convert(tz_ny)
    # 以纽约时间9:30为一天的分界
    def get_nyse_trading_day(dt):
        # dt为纽约时间
        if dt.time() >= time(9,30):
            return dt.date()
        else:
            return (dt - timedelta(days=1)).date()

    df['ny_trading_day'] = df['open_datetime_ny'].apply(get_nyse_trading_day).astype(str)
    # start和end参数也要转为date字符串
    start_dt = datetime.strptime(start, '%Y-%m-%d').date()
    end_dt = datetime.strptime(end, '%Y-%m-%d').date()
    mask = (df['ny_trading_day'] >= str(start_dt)) & (df['ny_trading_day'] <= str(end_dt))
    trades = df.loc[mask].copy()
    
    # 包含更多字段以支持配置化的列显示
    available_fields = ['index', 'symbol','open_datetime', 'close_datetime', 'open_price', 'close_price', 'open_qty', 'entry_reason', 'exit_reason', 'net_profit', 'direction', 'trade_type', 'holding_time', 'side']
    # 只选择DataFrame中实际存在的字段
    existing_fields = [field for field in available_fields if field in trades.columns]
    result = trades[existing_fields].fillna('').to_dict(orient='records')
    print("返回的交易数据:", result)

    return jsonify(result)

@app.route('/save_column_settings', methods=['POST'])
def save_column_settings():
    try:
        data = request.get_json()
        column_settings = data.get('columnSettings')
        page_length = data.get('pageLength')
        order = data.get('order')
        if not isinstance(column_settings, dict):
            return jsonify({'success': False, 'message': 'Invalid data'}), 400

        config_path = os.path.join(PROJECT_ROOT, 'static', 'config', 'trades_page.json')
        # 读取原有配置
        if os.path.exists(config_path):
            with open(config_path, 'r', encoding='utf-8') as f:
                config = json.load(f)
        else:
            config = {}

        config['columnSettings'] = column_settings
        if page_length is not None:
            config['pageLength'] = page_length
        if order is not None:
            config['order'] = order

        with open(config_path, 'w', encoding='utf-8') as f:
            json.dump(config, f, ensure_ascii=False, indent=4)

        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

@app.route('/api/trade_config')
def api_trade_config():
    config_path = os.path.join(PROJECT_ROOT, 'src', 'config', 'trade_config.json')
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            return jsonify(json.load(f))
    except Exception as e:
        return jsonify({})

@app.route('/api/symbol_config')
def api_symbol_config():
    """获取交易品种配置"""
    try:
        from src.config.symbol_config import SYMBOL_CONFIG
        print("SYMBOL_CONFIG", SYMBOL_CONFIG)
        return jsonify(SYMBOL_CONFIG)
    except Exception as e:
        return jsonify({})

@app.route('/api/statistics_config')
def api_statistics_config():
    """获取统计页面配置"""
    config_path = os.path.join(PROJECT_ROOT, 'src', 'config', 'statistics_config.json')
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            return jsonify(json.load(f))
    except Exception as e:
        print(f"Error loading statistics config: {e}")
        return jsonify({
            "modal_window_columns": {"display_columns": []},
            "best_worst_columns": {"display_columns": []},
            "dashboard_settings": {"default_k_value": 5},
            "calendar_settings": {"default_view": "day"},
            "chart_settings": {"show_equity_curve": True}
        })

@app.route('/api/statistics_config', methods=['POST'])
def save_statistics_config():
    """保存统计页面配置"""
    try:
        data = request.get_json()
        config_path = os.path.join(PROJECT_ROOT, 'src', 'config', 'statistics_config.json')
        
        # 确保目录存在
        os.makedirs(os.path.dirname(config_path), exist_ok=True)
        
        # 保存配置
        with open(config_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=4)
        
        return jsonify({'success': True, 'message': '配置保存成功'})
    except Exception as e:
        print(f"Error saving statistics config: {e}")
        return jsonify({'success': False, 'message': f'保存失败: {str(e)}'})

def apply_single_filter(df, field, operator, value):
    """应用单个过滤器条件"""
    if field not in df.columns:
        return df
    
    # 检查是否为日期时间字段
    datetime_fields = ['open_datetime', 'close_datetime']
    is_datetime_field = field in datetime_fields
    
    # 根据操作符构建条件
    if operator == 'equals':
        return df[df[field] == value]
    elif operator == 'not_equals':
        return df[df[field] != value]
    elif operator == 'contains':
        return df[df[field].str.contains(value, case=False, na=False)]
    elif operator == 'not_contains':
        return df[~df[field].str.contains(value, case=False, na=False)]
    elif operator == 'greater_than':
        if is_datetime_field:
            # 对于日期时间字段，转换为datetime进行比较
            try:
                value_dt = pd.to_datetime(value)
                return df[pd.to_datetime(df[field], errors='coerce') > value_dt]
            except:
                print(f"日期时间转换失败: {value}")
                return df
        else:
            # 对于数值字段，转换为数值进行比较
            return df[pd.to_numeric(df[field], errors='coerce') > float(value)]
    elif operator == 'less_than':
        if is_datetime_field:
            try:
                value_dt = pd.to_datetime(value)
                return df[pd.to_datetime(df[field], errors='coerce') < value_dt]
            except:
                print(f"日期时间转换失败: {value}")
                return df
        else:
            return df[pd.to_numeric(df[field], errors='coerce') < float(value)]
    elif operator == 'greater_than_or_equal':
        if is_datetime_field:
            try:
                value_dt = pd.to_datetime(value)
                return df[pd.to_datetime(df[field], errors='coerce') >= value_dt]
            except:
                print(f"日期时间转换失败: {value}")
                return df
        else:
            return df[pd.to_numeric(df[field], errors='coerce') >= float(value)]
    elif operator == 'less_than_or_equal':
        if is_datetime_field:
            try:
                value_dt = pd.to_datetime(value)
                return df[pd.to_datetime(df[field], errors='coerce') <= value_dt]
            except:
                print(f"日期时间转换失败: {value}")
                return df
        else:
            return df[pd.to_numeric(df[field], errors='coerce') <= float(value)]
    elif operator == 'is_null':
        return df[df[field].isna()]
    elif operator == 'is_not_null':
        return df[df[field].notna()]
    elif operator == 'is_empty':
        return df[df[field].isna() | (df[field] == '')]
    elif operator == 'is_not_empty':
        return df[df[field].notna() & (df[field] != '')]
    else:
        print(f"不支持的操作符: {operator}")
        return df

@app.route('/statistics/chart_data', methods=['GET'])
def get_chart_data():
    """获取图表数据"""
    try:
        print("=== 获取图表数据 ===")
        print(f"request.args: {request.args}")
        
        # 获取所有交易记录
        trades_df = trades_to_df(storage.get_trades())
        print(f"原始交易记录数: {len(trades_df)}")
        
        # 应用过滤器
        filters_applied = False
        
        # 检查是否有JSON格式的配置参数
        config_str = request.args.get('config')
        if config_str:
            try:
                config = json.loads(config_str)
                print(f"解析到配置: {config}")
                
                if 'filters' in config and config['filters']:
                    filters = config['filters']
                    print(f"应用过滤器: {filters}")
                    
                    # 新的逻辑：基于每个filter的logic属性来处理
                    if filters:
                        # 第一个过滤条件
                        result_df = trades_df.copy()
                        
                        # 处理第一个过滤条件
                        first_filter = filters[0]
                        field = first_filter.get('field')
                        operator = first_filter.get('operator')
                        value = first_filter.get('value')
                        
                        if field and operator and field in trades_df.columns:
                            try:
                                result_df = apply_single_filter(trades_df, field, operator, value)
                                print(f"第一个过滤器 {field} {operator} {value}, 匹配记录: {len(result_df)}")
                            except Exception as e:
                                print(f"第一个过滤条件应用失败: {e}")
                                result_df = pd.DataFrame()  # 空DataFrame
                        
                        # 处理后续过滤条件
                        for i in range(1, len(filters)):
                            filter_item = filters[i-1]  # 前一个filter决定逻辑关系
                            current_filter = filters[i]
                            
                            field = current_filter.get('field')
                            operator = current_filter.get('operator')
                            value = current_filter.get('value')
                            logic = filter_item.get('logic', 'and').lower()
                            
                            if field and operator and field in trades_df.columns:
                                try:
                                    temp_df = apply_single_filter(trades_df, field, operator, value)
                                    print(f"过滤器 {field} {operator} {value}, 匹配记录: {len(temp_df)}, 逻辑: {logic}")
                                    
                                    if logic == 'and':
                                        # AND逻辑：与前面结果的交集
                                        if not result_df.empty and not temp_df.empty:
                                            # 找到共同的记录
                                            common_indices = result_df.index.intersection(temp_df.index)
                                            result_df = result_df.loc[common_indices]
                                        else:
                                            result_df = pd.DataFrame()  # 如果任一为空，结果为空
                                    elif logic == 'or':
                                        # OR逻辑：与前面结果的并集
                                        if not temp_df.empty:
                                            result_df = pd.concat([result_df, temp_df]).drop_duplicates()
                                        # 如果temp_df为空，保持result_df不变
                                    
                                    print(f"应用 {logic} 逻辑后，结果记录数: {len(result_df)}")
                                    
                                except Exception as e:
                                    print(f"过滤条件 {field} {operator} {value} 应用失败: {e}")
                        
                        trades_df = result_df
                        filters_applied = True
                        print(f"最终过滤结果: {len(trades_df)} 条记录")
            except json.JSONDecodeError as e:
                print(f"JSON解析失败: {e}")
            except Exception as e:
                print(f"配置处理失败: {e}")
        
        # 如果没有JSON配置，尝试处理传统格式的过滤器参数
        if not filters_applied:
            filter_index = 0
            while f'filter_{filter_index}_field' in request.args:
                field = request.args.get(f'filter_{filter_index}_field')
                operator = request.args.get(f'filter_{filter_index}_operator')
                value = request.args.get(f'filter_{filter_index}_value')
                
                if field and operator and field in trades_df.columns and not trades_df.empty:
                    try:
                        trades_df = apply_single_filter(trades_df, field, operator, value)
                        print(f"传统过滤器 {field} {operator} {value}, 剩余记录: {len(trades_df)}")
                    except Exception as e:
                        print(f"过滤条件 {filter_index} 应用失败: {e}")
                
                filter_index += 1
        
        # 转换为JSON格式
        trade_data = []
        for _, trade in trades_df.iterrows():
            
            # 安全的datetime转换函数
            def safe_datetime_to_iso(dt_value):
                if pd.isna(dt_value) or dt_value is None:
                    return None
                if hasattr(dt_value, 'isoformat'):
                    return dt_value.isoformat()
                if isinstance(dt_value, str):
                    try:
                        # 尝试解析字符串为datetime
                        parsed_dt = pd.to_datetime(dt_value)
                        return parsed_dt.isoformat()
                    except:
                        return dt_value  # 如果解析失败，返回原字符串
                return str(dt_value)
            
            # 安全的数值转换函数
            def safe_float(value, default=0):
                if pd.isna(value) or value is None:
                    return default
                try:
                    return float(value)
                except (ValueError, TypeError):
                    return default
            
            # 安全的字符串转换函数
            def safe_str(value):
                if pd.isna(value) or value is None:
                    return None
                return str(value)
            
            trade_dict = {
                # 基本信息
                'id': trade.get('id'),
                'index': safe_float(trade.get('index')),
                'trade_id': safe_str(trade.get('trade_id')),
                'symbol': safe_str(trade.get('symbol')),
                'direction': safe_str(trade.get('direction')),
                'side': safe_str(trade.get('side')),
                'trade_type': safe_str(trade.get('trade_type')),
                'session': safe_str(trade.get('session')),
                'nth_trade': safe_float(trade.get('nth_trade')),
                
                # 价格和数量
                'open_price': safe_float(trade.get('open_price')),
                'close_price': safe_float(trade.get('close_price')),
                'open_qty': safe_float(trade.get('open_qty')),
                'close_qty': safe_float(trade.get('close_qty')),
                
                # 时间相关
                'open_datetime': safe_datetime_to_iso(trade.get('open_datetime')),
                'close_datetime': safe_datetime_to_iso(trade.get('close_datetime')),
                'holding_time': safe_str(trade.get('holding_time')),
                
                # 订单类型
                'open_order_type': safe_str(trade.get('open_order_type')),
                'close_order_type': safe_str(trade.get('close_order_type')),
                
                # 盈亏相关
                'net_profit': safe_float(trade.get('net_profit')),
                'gross_profit': safe_float(trade.get('gross_profit')),
                'commission': safe_float(trade.get('commission')),
                'point_profit_per_lot': safe_float(trade.get('point_profit_per_lot')),
                'total_points': safe_float(trade.get('total_points')),
                
                # 浮盈浮亏
                'max_floating_profit_points': safe_float(trade.get('max_floating_profit_points')),
                'max_floating_profit_dollars': safe_float(trade.get('max_floating_profit_dollars')),
                'max_floating_loss_points': safe_float(trade.get('max_floating_loss_points')),
                'max_floating_loss_dollars': safe_float(trade.get('max_floating_loss_dollars')),
                
                # 交易原因
                'entry_reason': safe_str(trade.get('entry_reason')),
                'exit_reason': safe_str(trade.get('exit_reason')),
                
                # 止损止盈
                'stop_loss_price': safe_float(trade.get('stop_loss_price')),
                'stop_loss_reason': safe_str(trade.get('stop_loss_reason')),
                'take_profit_price': safe_float(trade.get('take_profit_price')),
                'take_profit_reason': safe_str(trade.get('take_profit_reason')),
                
                # 评价指标
                'rating': safe_float(trade.get('rating')),
                'evaluation': safe_str(trade.get('evaluation')),
                'open_rrr': safe_float(trade.get('open_rrr')),
                'close_rrr': safe_float(trade.get('close_rrr')),
                'fwr': safe_float(trade.get('fwr')),
            }
            trade_data.append(trade_dict)
        
        print(f"返回 {len(trade_data)} 条交易记录")
        
        return jsonify({
            'trades': trade_data,
            'total': len(trade_data),
            'status': 'success'
        })
        
    except Exception as e:
        print(f"获取图表数据失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    # 确保data目录存在
    if not os.path.exists('data'):
        os.makedirs('data')
    # 设置工作目录为当前文件所在目录
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    # 修改host为0.0.0.0，允许外部访问
    app.run(host='0.0.0.0', port=5000, debug=True)